package com.settlement.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.settlement.system.common.base.IBaseEnum;
import com.settlement.system.common.constant.SystemConstants;
import com.settlement.system.common.enums.StoreStatusEnum;
import com.settlement.system.common.model.Option;
import com.settlement.system.common.util.DateUtils;
import com.settlement.system.common.util.SecurityUtils;
import com.settlement.system.mapper.SysStoreMapper;
import com.settlement.system.model.entity.SysCompany;
import com.settlement.system.model.entity.SysPlatform;
import com.settlement.system.model.entity.SysStore;
import com.settlement.system.model.form.BillLockForm;
import com.settlement.system.model.form.StoreForm;
import com.settlement.system.model.query.StorePageQuery;
import com.settlement.system.model.vo.StoreExportVO;
import com.settlement.system.model.vo.StoreVO;
import com.settlement.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 店铺业务实现类
 *
 * @author haoxr
 * @since 2022/1/14
 */
@Service
@RequiredArgsConstructor
public class SysStoreServiceImpl extends ServiceImpl<SysStoreMapper, SysStore> implements SysStoreService {

    private final SysDictTypeService dictTypeService;

    private final SysBillLockService sysBillLockService;

    private final SysCompanyService companyService;

    private final SysDictService dictService;

    private final RedisTemplate redisTemplate;

    @Override
    public Page<SysStore> getStorePage(StorePageQuery queryParams) {
        // 查询参数
        int pageNum = queryParams.getPageNum();
        int pageSize = queryParams.getPageSize();
        String keywords = queryParams.getKeywords();
        // 查询数据
        Page<SysStore> page = this.page(new Page<>(pageNum, pageSize), new LambdaQueryWrapper<SysStore>().like(StrUtil.isNotBlank(keywords), SysStore::getCommercePlatformStoreCode, keywords).or().like(StrUtil.isNotBlank(keywords), SysStore::getCommercePlatformStoreName, keywords).orderByDesc(SysStore::getUpdateTime));
        if(page.getRecords().size() > 0){
            List<SysCompany> sysCompanyList = companyService.list();
            List<Option> optionList = dictService.listDictOptions(SystemConstants.PLATFORM_KEY);
            SysCompany company;
            Option option;
            for (SysStore record : page.getRecords()) {
                record.setStatusName(IBaseEnum.getLabelByValue(record.getStatus(), StoreStatusEnum.class));
                company = sysCompanyList.stream().filter(item -> Objects.equals(item.getCode(), record.getCompanyCode())).findFirst().orElse(null);
                if(Objects.nonNull(company)){
                    record.setCompanyName(company.getName());
                }
                option = optionList.stream().filter(item -> Objects.equals(item.getValue(), record.getStoreKey())).findFirst().orElse(null);
                if(Objects.nonNull(option)){
                    record.setPlatformName(option.getLabel());
                }
            }
        }
        return page;
    }

    @Override
    public SysStore getStoreFormData(Long storeId) {
        return this.baseMapper.selectById(storeId);
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean saveStore(StoreForm storeForm) {
        // 实体转换 form->entity
        SysStore store = new SysStore();
        BeanUtil.copyProperties(storeForm, store);
        long count;
        if (storeForm.getId() == null) {
            count = this.count(new LambdaQueryWrapper<SysStore>().eq(SysStore::getCommercePlatformStoreCode, storeForm.getCommercePlatformStoreCode()));
        } else {
            count = this.count(new LambdaQueryWrapper<SysStore>().eq(SysStore::getCommercePlatformStoreCode, storeForm.getCommercePlatformStoreCode()).ne(SysStore::getId, storeForm.getId()));
        }
        Assert.isTrue(count == 0, "电商平台店铺编码已存在");
        // 生成核销锁账
        BillLockForm billLockForm = new BillLockForm();
        billLockForm.setCommercePlatformStoreCode(storeForm.getCommercePlatformStoreCode());
        sysBillLockService.saveBillLock(billLockForm);
        // 删除缓存
        if (store.getId() != null) {
            redisTemplate.delete(SystemConstants.STORE_CACHE_PREFIX + store.getId());
        }
        return saveOrUpdate(store);
    }

    @Override
    @SuppressWarnings("unchecked")
    public boolean deleteStores(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的店铺数据为空");
        // 逻辑删除
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).collect(Collectors.toList());
        List<SysStore> sysStores = this.list(new LambdaQueryWrapper<SysStore>().in(SysStore::getId, ids));
        List<String> codeList = sysStores.stream().map(SysStore::getCommercePlatformStoreCode).toList();
        // 同步删除核销锁账数据
        sysBillLockService.deleteByCodeList(codeList);
        for (Long id : ids) {
            // 删除缓存
            redisTemplate.delete(SystemConstants.STORE_CACHE_PREFIX + id);
        }
        return this.removeByIds(ids);
    }

    @Override
    public List<SysStore> getByCompanyCode(String companyCode) {
        return this.list(new LambdaQueryWrapper<SysStore>().eq(SysStore::getCompanyCode, companyCode));
    }

    @Override
    public List<StoreVO> getListByStoreKey(String storeKey) {
        List<SysStore> storeList = this.list(new LambdaQueryWrapper<SysStore>().eq(SysStore::getStoreKey, storeKey));
        List<StoreVO> voList = new ArrayList<>();
        for (SysStore store : storeList) {
            StoreVO vo = new StoreVO();
            BeanUtil.copyProperties(store, vo);
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public List<StoreVO> getAllStore() {
        List<Option> platformList = dictTypeService.listDictItemsByTypeCode(SystemConstants.PLATFORM_KEY);
        List<SysStore> storeList = this.list();
        List<StoreVO> voList = new ArrayList<>();
        for (SysStore store : storeList) {
            StoreVO vo = new StoreVO();
            BeanUtil.copyProperties(store, vo);
            vo.setStoreKeyName(platformList.stream().filter(platform -> platform.getValue().equals(store.getStoreKey())).findFirst().map(Option::getLabel).orElse(null));
            voList.add(vo);
        }
        return voList;
    }

    @Override
    @SuppressWarnings("unchecked")
    public SysStore getById(Long storeId) {
        Object value = redisTemplate.opsForValue().get(SystemConstants.STORE_CACHE_PREFIX + storeId);
        if (value != null) {
            return (SysStore) value;
        }
        SysStore sysStore = this.baseMapper.selectById(storeId);
        redisTemplate.opsForValue().set(SystemConstants.STORE_CACHE_PREFIX + storeId, sysStore, 1, TimeUnit.HOURS);
        return sysStore;
    }

    @Override
    @SuppressWarnings("unchecked")
    public SysStore getByCode(String code) {
        Object value = redisTemplate.opsForValue().get(SystemConstants.STORE_CACHE_PREFIX + code);
        if (value != null) {
            return (SysStore) value;
        }
        SysStore sysStore = this.baseMapper.selectOne(new LambdaQueryWrapper<SysStore>().eq(SysStore::getCommercePlatformStoreCode, code));
        redisTemplate.opsForValue().set(SystemConstants.STORE_CACHE_PREFIX + code, sysStore, 1, TimeUnit.HOURS);
        return sysStore;
    }

    @Override
    public SysStore getByInnerSystemStoreCode(String innerSystemStoreCode) {
        Object value = redisTemplate.opsForValue().get(SystemConstants.INNER_STORE_CACHE_PREFIX + innerSystemStoreCode);
        if (value != null) {
            return (SysStore) value;
        }
        SysStore sysStore =
                this.baseMapper.selectOne(new LambdaQueryWrapper<SysStore>().eq(SysStore::getInnerSystemStoreCode,
                        innerSystemStoreCode));
        redisTemplate.opsForValue().set(SystemConstants.INNER_STORE_CACHE_PREFIX + innerSystemStoreCode, sysStore, 1, TimeUnit.HOURS);
        return sysStore;
    }

    @Override
    @SuppressWarnings("unchecked")
    public SysStore getByName(String name) {
        Object value = redisTemplate.opsForValue().get(SystemConstants.STORE_CACHE_PREFIX + name);
        if (value != null) {
            return (SysStore) value;
        }
        SysStore sysStore =
                this.baseMapper.selectOne(new LambdaQueryWrapper<SysStore>().eq(SysStore::getCommercePlatformStoreName,
                        name));
        redisTemplate.opsForValue().set(SystemConstants.STORE_CACHE_PREFIX + name, sysStore, 1, TimeUnit.HOURS);
        return sysStore;
    }

    @Override
    public void disableStores(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "禁用的店铺数据为空");
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).toList();
        List<SysStore> storeList = this.getBaseMapper().selectBatchIds(ids);
        storeList.forEach(item -> item.setStatus(StoreStatusEnum.DISABLE.getValue()));
        this.saveOrUpdateBatch(storeList);
    }

    @Override
    public void enableStores(String idsStr) {
        Assert.isTrue(StrUtil.isNotBlank(idsStr), "启用的店铺数据为空");
        List<Long> ids = Arrays.stream(idsStr.split(",")).map(Long::parseLong).toList();
        List<SysStore> storeList = this.getBaseMapper().selectBatchIds(ids);
        storeList.forEach(item -> item.setStatus(StoreStatusEnum.ENABLE.getValue()));
        this.saveOrUpdateBatch(storeList);
    }

    @Override
    public void importStores(List<StoreExportVO> vos) {
        List<SysStore> storeList = this.list();
        List<SysCompany> companyList = companyService.list();
        List<Option> optionList = dictTypeService.listDictItemsByTypeCode(SystemConstants.PLATFORM_KEY);
        SysStore store;
        SysCompany company;
        Option option;
        for (StoreExportVO vo : vos) {
            company = companyList.stream().filter(item -> Objects.equals(item.getName(), vo.getCompanyName())).findFirst().orElse(null);
            Assert.isTrue(Objects.nonNull(company), "导入店铺数据失败，公司名称【%s】不存在".formatted(vo.getCompanyName()));
            option = optionList.stream().filter(item -> Objects.equals(item.getLabel(), vo.getPlatformName())).findFirst().orElse(null);
            Assert.isTrue(Objects.nonNull(option), "导入店铺数据失败，平台名称【%s】不存在".formatted(vo.getPlatformName()));
        }
        int count = 0;
        String now = LocalDateTime.now().toLocalDate().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        Object value = redisTemplate.opsForValue().get(SystemConstants.STORE_CODE_CACHE_PREFIX + now);
        if (Objects.nonNull(value)) {
            count = (Integer) value;
        }
        for (StoreExportVO vo : vos) {
            store = storeList.stream().filter(item -> Objects.equals(item.getBillSystemStoreCode(), vo.getBillSystemStoreCode())).findFirst().orElse(null);
            if(Objects.isNull(store)){
                store = new SysStore();
                BeanUtil.copyProperties(vo, store);
                company = companyList.stream().filter(item -> Objects.equals(item.getName(), vo.getCompanyName())).findFirst().orElse(null);
                if(Objects.nonNull(company)){
                    store.setCompanyCode(company.getCode());
                }
                option = optionList.stream().filter(item -> Objects.equals(item.getLabel(), vo.getPlatformName())).findFirst().orElse(null);
                if(Objects.nonNull(option)){
                    store.setStoreKey(option.getValue().toString());
                }
                store.setCreateBy(SecurityUtils.getUserId());
                store.setBillSystemStoreCode("SHOP" + Long.parseLong(DateUtils.getDateString().substring(0, 11))+String.format("%03d", count));
                this.save(store);
                count++;
            }else{
                BeanUtils.copyProperties(vo, store);
                // 删除缓存
                redisTemplate.delete(SystemConstants.STORE_CACHE_PREFIX + store.getId());
                this.updateById(store);
            }
        }
        redisTemplate.opsForValue().set(SystemConstants.STORE_CODE_CACHE_PREFIX + now, count, 2, TimeUnit.DAYS);
    }
}
